<template>
  <div
    :class="animate"
    :style="{ height: height, width: width }"
    :id="chartOption.bindingDiv"
    ref="chartDiv"
  />
</template>

<script>
import echarts from "echarts";
require("echarts/theme/macarons"); // echarts theme
import resize from "@/views/dashboard/mixins/resize";

import "../../animate/animate.css";

import { parseQueryString, fIsUrL } from "../../util/urlUtil";
import { chartApiBar, remoteChartApi ,chartBIanalysis } from "@/api/tool/datav/chartApi";
import { linkChart } from "../../util/LinkageChart";
import { addOption } from "../../codegen/codegen";
import { topbarBIAnalysis } from "@/api/tool/datav/chartBI/chartTopBarBI";
import { getFormsource } from "@/api/tool/datav/formsource";
import VueEvent from "@/views/tool/datav/VueEvent";
import { websocketCommand } from "../../util/websocket.js";
const animationDuration = 6000;

export default {
  mixins: [resize],
  props: {
    className: {
      type: String,
      default: "chart"
    },
    width: {
      type: String,
      default: "100%"
    },
    height: {
      type: String,
      default: "100%"
    },
    chartOption: {
      type: Object
    },
    drawingList: {
      type: Array
    }
  },
  data() {
    return {
      chart: null,
      //dataOption: this.chartOption,
      timer: "",
      wsObj: null,
      wsFlag: false,
      wsTimer: "",
      wsValue: null,
      animate: this.className
    };
  },
  watch: {
    width() {
      this.$nextTick(() => {
        this.chart.resize();
      });
    },
    height() {
      this.$nextTick(() => {
        this.chart.resize();
      });
    },
    chartOption: {
      deep: true,
      handler(newVal) {
        this.$nextTick(() => {
          this.setOptions(JSON.parse(JSON.stringify(newVal)));
        });
      }
    },

    "chartOption.theme": {
      handler() {
        if (this.chart != null) {
          this.chart.dispose();
          this.chart = null;
          this.initChart();
        }
      }
    },
    "chartOption.timeout": {
      handler() {
        this.chart.dispose();
        this.chart = null;
        this.initChart();
      }
    },
    "chartOption.dataSourceType": {
      handler(value) {
        //切换数据源重新连接
        if (value !== "websocket") {
          this.wsFlag = false;
          //每次切换数据源恢复原来动画
          this.animate = this.className;
        }
        if (value !== "url") {
          clearTimeout(this.timer);
        } 
      }
    },
    "chartOption.interfaceKey": {
      handler(newValue, oldValue) {
        //初始化不创建连接，改变接口地址重新创建
        if (oldValue !== undefined && oldValue != "") {
          this.wsValue = null;
          this.closeWs();
          this.createWs();
          this.animate = this.className;
        }
      }
    },
    wsFlag: {
      handler(value) {
        if (!value) {
          this.wsValue = null;
          this.closeWs();
        }
      }
    },
    className: {
      handler(value) {
        this.animate = value;
      }
    }
  },
  mounted() {
    this.$nextTick(() => {
      this.initChart();
    });
  },
  beforeDestroy() {
    if (!this.chart) {
      return;
    }
    this.chart.dispose();
    this.chart = null;
    clearTimeout(this.timer);
    if (this.wsFlag) {
      this.closeWs();
    }
  },
  methods: {
    initChart() {
      echarts.registerTheme("customTheme", this.chartOption.theme);
      this.chart = echarts.init(this.$el, "customTheme");
     
      //判断是否开启定时器，当是访问url接口时候并且timeout不为0时候开启定时器
      if (this.timer != "") {
        clearTimeout(this.timer);
      }
      if (
        (this.chartOption.dataSourceType == 'url' || this.chartOption.dataSourceType == 'database') &&
        this.chartOption.timeout > 0
      ) {
        let timerTask = () => {
          this.setOptions(JSON.parse(JSON.stringify(this.chartOption)));
          this.timer = setTimeout(() => {
            timerTask();
          }, this.chartOption.timeout);
        };

        timerTask();
      }else{
         this.setOptions(JSON.parse(JSON.stringify(this.chartOption)));
      }
    },
    setOptions: async function(dataOption) {
      //初始化数据
      //如果不是静态数据就调用接口给staticDataValue赋值
      if (dataOption.dataSourceType == "url") {
        let paramJson = parseQueryString(dataOption.requestParameters);

        let interfaceURL = dataOption.interfaceURL;
        dataOption.staticDataValue = await chartApiBar(
          dataOption.requestMethod,
          interfaceURL,
          paramJson,
          dataOption.token
        );
      } else if (dataOption.dataSourceType == "database") {
        if (
          dataOption.database.executeSql != undefined &&
          dataOption.database.executeSql != ""
        ) {
          let result = [];
          if(dataOption.database.sqlType != 'custom'){
          
            result = await topbarBIAnalysis(dataOption.database);
          }else{
            result = await chartBIanalysis(dataOption.database);
          }
          if (result.code == 200) {
            dataOption.staticDataValue = result.data;
          } else {
            alert("操作数据库错误");
          }
        }
      } else if (dataOption.dataSourceType == "form") {
        if (dataOption.formSource != undefined) {
          let response = await getFormsource(dataOption.formSource.id);
          dataOption.staticDataValue = JSON.parse(response.data.formData);
        }
      } else if (dataOption.dataSourceType == "websocket") {
        if (
          dataOption.interfaceKey != undefined &&
          dataOption.interfaceKey != ""
        ) {
          if (!this.wsFlag) {
            this.wsFlag = true;
            this.wsValue = null;
            this.createWs();
          }
          if (this.wsValue != null) {
            dataOption.staticDataValue = this.wsValue;
          }
        }
      }

      let charts = Array.from(dataOption.staticDataValue); //es6 数组拷贝

      if (dataOption.isThemeColor == true) {
        //获取主题颜色
        let customcolor = this.chartOption.theme.color;
        for (var i = 0; i < dataOption.color.length; i++) {
          dataOption.color[i].color0 = customcolor[i % customcolor.length];
        }
      }

      let length = dataOption.color.length;
      if (length < dataOption.staticDataValue.length) {
        for (let i = length; i < dataOption.staticDataValue.length; i++) {
          let cblock = dataOption.color[i % length];
          dataOption.color.push(cblock);
        }
      } else if (length > dataOption.staticDataValue.length) {
        dataOption.color = dataOption.color.slice(
          0,
          dataOption.staticDataValue.length
        );
      }
      //排序  start-----------------------------------------------------------
      if (dataOption.order == "ascend") {
        for (let i = 0; i < charts.length - 1; i++) {
          for (let j = i + 1; j < charts.length; j++) {
            if (charts[i].value < charts[j].value) {
              let data = charts[i];
              charts[i] = charts[j];
              charts[j] = data;
            }
          }
        }
      } else if (dataOption.order == "descend") {
        //降序
        for (let i = 0; i < charts.length - 1; i++) {
          for (let j = i + 1; j < charts.length; j++) {
            if (charts[i].value > charts[j].value) {
              let data = charts[i];
              charts[i] = charts[j];
              charts[j] = data;
            }
          }
        }
      }
      // 排序 end-------------------------------------------------------------

      //圆角显示
      let raduis = dataOption.radius == undefined ? 12 : dataOption.radius;
      if (dataOption.radiusShow == undefined) {
        raduis = 12;
      } else {
        if (!dataOption.radiusShow) {
          raduis = 0;
        }
      }

      let top10CityList = [];
      let top10CityData = [];
      let top10CityDataY = [];
      let color = [];
      let lineY = [];
      let llength = charts.length;
      for (let i = 0; i < llength; i++) {
        let x = i;
        x %= dataOption.color.length;

        top10CityDataY.push(charts[llength - i - 1].value);
        top10CityList.push(charts[i].name);
        top10CityData.push(charts[i].value);
        color.push(dataOption.color[x].color0);
        let data = {
          name: charts[i].name,
          color: dataOption.color[x].color0,
          value: top10CityData[i],
          itemStyle: {
            normal: {
              show: true,
              color: new echarts.graphic.LinearGradient(
                0,
                0,
                1,
                0,
                [
                  {
                    offset: 0,
                    color: dataOption.color[x].color0
                  },
                  {
                    offset: 1,
                    color: dataOption.color[x].color1
                  }
                ],
                false
              ),
              barBorderRadius: raduis
            },
            emphasis: {
              shadowBlur: 15,
              shadowColor: "rgba(0, 0, 0, 0.1)"
            }
          }
        };
        lineY.push(data);
      }

      //是否显示标题 start-----------------------------------------
      if (dataOption.istitle == false) {
        dataOption.title.show = false;
      } else {
        dataOption.title.show = true;
      }

      dataOption.valueLabel.formatter = "{value}" + dataOption.suf;

      if (dataOption.customPosition) {
        dataOption.label.position = [
          dataOption.leftPositon + "%",
          dataOption.topPositon + "%"
        ];
      }

      let option = {
        backgroundColor: "rgba(0,0,0,0)",
        title: {
          show: dataOption.istitle == false ? false : true,
          text: dataOption.title.text,
          textStyle: {
            color: "#fff", //颜色
            fontStyle: "normal", //风格
            fontWeight: "normal", //粗细
            //fontFamily: 'Microsoft yahei',   //字体
            //fontSize: 20,     //大小
            align: "center" //水平对齐
          },
          subtext: dataOption.title.subtext, //副标题
          subtextStyle: {
            //对应样式
            color: "#fff",
            fontSize: 14,
            align: "center"
          },
          itemGap: 7
        },
        tooltip: {
          trigger: "item"
        },
        grid: {
          left: dataOption.label.position == "left" ? "20%" : "3%"
        },
        color: color,
        yAxis: [
          {
            type: "category",
            name: dataOption.yAxisName,
            nameTextStyle: {
              color: dataOption.label.textStyle.color,
              fontSize: dataOption.label.textStyle.fontSize,
              fontFamily: dataOption.label.textStyle.fontFamily
            },
            inverse: false,
            axisTick: {
              show: false
            },
            axisLine: {
              show:
                dataOption.yLineShow == undefined
                  ? false
                  : dataOption.yLineShow,
              lineStyle: {
                color:
                  typeof dataOption.yLineColor == "undefined"
                    ? "#fff"
                    : dataOption.yLineColor == null
                    ? "transparent"
                    : dataOption.yLineColor,
                width:
                  dataOption.yLineWidth == undefined ? 1 : dataOption.yLineWidth
              }
            },
            axisLabel: {
              show: false,
              inside: false
            },
            data: top10CityList
          },
          {
            type: "category",
            axisLine: {
              show: false
            },
            axisTick: {
              show: false
            },
            axisLabel: dataOption.valueLabel,
            splitArea: {
              show: false
            },
            splitLine: {
              show: false
            },
            data: top10CityData, //右侧数据
            show:
              dataOption.valueLabelShow == undefined
                ? true
                : dataOption.valueLabelShow
          }
        ],
        xAxis: {
          type: "value",
          name: dataOption.xAxisName,
          nameTextStyle: {
            color:
              typeof dataOption.xFontColor == "undefined"
                ? "#fff"
                : dataOption.xFontColor == null
                ? "transparent"
                : dataOption.xFontColor,
            fontSize:
              typeof dataOption.xFontSize == "undefined"
                ? 0
                : dataOption.xFontSize
          },
          axisTick: {
            show: false
          },
          axisLine: {
            show:
              dataOption.xLineShow == undefined ? false : dataOption.xLineShow,
            lineStyle: {
              color:
                typeof dataOption.xLineColor == "undefined"
                  ? "#fff"
                  : dataOption.xLineColor == null
                  ? "transparent"
                  : dataOption.xLineColor,
              width:
                dataOption.xLineWidth == undefined ? 1 : dataOption.xLineWidth
            }
          },
          splitLine: {
            show:
              dataOption.splitLineShow == undefined
                ? false
                : dataOption.splitLineShow,
            lineStyle: {
              color:
                dataOption.splitLineColor == undefined
                  ? "#ccc"
                  : dataOption.splitLineColor,
              width:
                dataOption.splitLineWidth == undefined
                  ? 1
                  : dataOption.splitLineWidth,
              type:
                dataOption.splitLineStyle == undefined
                  ? "solid"
                  : dataOption.splitLineStyle
            }
          },
          axisLabel: {
            textStyle: {
              show: true,
              color:
                typeof dataOption.xFontColor == "undefined"
                  ? "transparent"
                  : dataOption.xFontColor == null
                  ? "transparent"
                  : dataOption.xFontColor,
              fontSize:
                typeof dataOption.xFontSize == "undefined"
                  ? 0
                  : dataOption.xFontSize
            }
          }
        },
        series: [
          {
            name: "",
            type: "bar",
            zlevel: 2,
            barWidth: dataOption.width,
            data: lineY,
            animationDuration: 1500,
            label: dataOption.label
          }
        ],
        animationEasing: "cubicOut"
      };
      dataOption.label.formatter = function(a, b) {
        return a.name;
      };

      //执行通用处理函数
      if(dataOption.customData != undefined && dataOption.customData != ""){
        try {
          option = (
          
            //里面为要处理的代码块
          eval(dataOption.customData) 
          
          )(
            option,
            dataOption.staticDataValue,
            this.$refs.chartDiv
          );
        } catch (error) {
          console.log(error)
        }
       } 
        //交互组件配置
      if(dataOption.interactData != undefined && dataOption.interactData != ""){
          try {
              option = (        
              //里面为要处理的代码块
              eval(dataOption.interactData)             
            )(
            option,
            dataOption.staticDataValue,
            this.$refs.chartDiv
            );
          } catch (error) {
            console.log(error)
          }               
       }
      this.chart.setOption(option, true);

      addOption(dataOption.bindingDiv, option);
      //开启图表联动
      if (dataOption.isLink == true) {
        this.chart.off("click");
        this.chart.on("click", params => {
          //设置参数
          let arrObject = {
            seriesName: params.name,
            data: params.value
          };

          let arrs = JSON.stringify(arrObject);

          //获取绑定的图表
          let bindList = this.chartOption.bindList;

          if (bindList.length > 0) {
            linkChart(dataOption.arrName, arrs, bindList, this.drawingList);
          }
        });
      }
      //开启图表下钻
      else if (dataOption.isDrillDown == true) {
        this.chart.off("click");
        this.chart.on("click", params => {
          //设置参数
          let arrObject = {
            seriesName: params.name,
            data: params.value
          };

          let arrs = JSON.stringify(arrObject);

          //获取绑定的图表
          let drillDownChartOption = this.chartOption.drillDownChartOption;

          if (
            drillDownChartOption != undefined &&
            drillDownChartOption != null
          ) {
            this.$set(
              this.chartOption.drillDownChartOption.chartOption,
              "requestParameters",
              "drillParam=" + arrs
            );
            //发送下钻消息
            VueEvent.$emit(
              "drill_down_msg",
              this.chartOption.drillDownChartOption
            );
          }
        });
      } else {
        //关闭图表联动，取消echart点击事件
        this.chart.off("click");
      }

      //开启远程图表控制
      if (dataOption.isRemote == true) {
        if (dataOption.remote != undefined && dataOption.remote != null) {
          this.chart.off("click");
          this.chart.on("click", params => {
            //设置参数
            let arrObject = {
              seriesName: params.seriesName,
              data: params.value
            };

            let remoteData = { ...dataOption.remote };
            remoteData.query = arrObject;
            //调用接口
            remoteChartApi(remoteData);
          });
        }
      }
    },
    //  ws连接成功，后台返回的ws数据
    receiveMsg(e) {
      if (e.action == "chat") {
        // console.log('服务端推送',e);
        this.wsValue = JSON.parse(e.result);
        this.setOptions(JSON.parse(JSON.stringify(this.chartOption)));
      }
    },
    // 建立连接、发起ws请求，以心跳方式，向服务端发送数据
    createWs() {
      this.wsObj = new WebSocket(process.env.VUE_APP_WEBSOCKET);
      // 若为对象类型，以回调方式发送
      websocketCommand(
        this.wsObj,
        "create",
        5000,
        this.chartOption.interfaceKey,
        this.sendHeartBeat,
        this.receiveMsg,
        this.reconnectWs,
        this.wsWarning
      );
    },
    // 断网重连，需要处理的逻辑
    reconnectWs() {
      if (this.wsObj) {
        console.log("%c websocket_reconnect", "color:blue");
        this.createWs();
      }
    },
    // 以回调方式向服务端发送(对象类型的)心跳
    sendHeartBeat() {
      if (this.wsTimer != "") {
        clearTimeout(this.wsTimer);
      }

      let wsTimerTask = () => {
        console.log("发送心跳", "ping");
        let obj = { action: "keep", key: this.chartOption.interfaceKey };
        this.wsObj.send(JSON.stringify(obj));
        this.wsTimer = setTimeout(() => {
          wsTimerTask();
        }, parseInt(process.env.VUE_APP_WEBSOCKET_TIMEOUT));
        this.wsWarning();
      };

      wsTimerTask();
    },
    wsWarning() {
      //如果断开连接则显示组件警告动画并清除计数器
      if (this.wsObj.readyState == 3) {
        this.animate = "warning";
        clearTimeout(this.wsTimer);
      }
    },
    closeWs() {
      clearTimeout(this.wsTimer);
      websocketCommand(
        this.wsObj,
        "close",
        5000,
        this.chartOption.interfaceKey,
        this.sendHeartBeat,
        this.receiveMsg,
        this.reconnectWs,
        this.wsWarning
      );
      this.wsObj = null;
    }
  }
};
</script>
